from . import passport_blu
from flask import request, jsonify, current_app, make_response, session
from info333.utils.response_code import RET
from info333.utils.captcha.captcha import captcha
from info333 import code_redis, constants, db
import re
from info333.models import User
import random
from info333.libs.yuntongxun import sms


# 1.获取图片验证码
@passport_blu.route('/imageCode')
def make_image_code():
    # 1.获取请求中的查询字符串中的uuid
    image_code_id = request.args.get('image_code_id')
    # 2.判断参数是否存在
    if not image_code_id:
        return jsonify(errno=RET.PARAMERR, errmsg='参数不存在')
    # 3.生成图片验证码
    name, text, image = captcha.generate_captcha()
    print(text)
    # 4.保存图片验证码
    try:
        code_redis.setex('ImageId-' + image_code_id, constants.IMAGE_CODE_REDIS_EXPIRES, text)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='验证码保存失败')
    else:
        # 5.将图片验证码响应给前端
        response = make_response(image)
        response.headers['Content-Type'] = 'image/jpg'
        return response


# 2.发送短信验证码
@passport_blu.route('/smsCode', methods=['POST'])
def sendSmsCode():
    # 1.获取前端用户输入的手机号/验证码,以及前端请求验证码时生成的验证码编号
    mobile = request.json.get('mobile')
    image_code = request.json.get('imageCode')
    image_code_id = request.json.get('imageCodeId')
    print(image_code)
    # 2.判断数据完整性
    if not all([mobile, image_code, image_code_id]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数不完整')

    # 既然数据完整，则进行逐步验证
    # 3.验证手机号，通过正则进行验证
    if not re.match(r'^1[3456789]\d{9}$', mobile):
        return jsonify(errno=RET.DATAERR, errmsg='手机号格式不正确')

    # 手机号验证通过后，需要验证验证码是否正确，首先应该先查询redis数据库中的官方验证码
    # 4.获取redis中的验证码
    try:
        official_image_code = code_redis.get('ImageId-' + image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='验证码已过期')
    # 5.验证码未过期，则在查询后，需要删除redis中的验证码，因为实际业务逻辑中，验证码只会使用一次后即失效
    try:
        code_redis.delete('ImageId-' + image_code_id)
    except Exception as e:
        # 如果删除验证码时发生异常，可以不用return，因为验证码可以自动过期。等待其自动失效即可
        current_app.logger.error(e)
    # 6.将数据库中的验证码和前端输入的验证码进行比较，注意：验证码不区分大小写
    if image_code.lower() != official_image_code.lower():
        return jsonify(errno=RET.DATAERR, errmsg='验证码不正确')
    # 验证码验证通过后，则需要处理发送短信的阶段，但发送短信之前，应该先判断用户是否已经注册
    # 7.判断用户是否已经注册
    # 7.1 查询数据库，判断用户是否已注册
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='数据查询异常')
    else:
        if user:
            return jsonify(errno=RET.DATAEXIST, errmsg='该用户已注册')
    # 确认用户未注册后，则可以向用户发送短信验证码：发送短信的功能由第三方模块：云通讯完成；而验证码则
    # 由后端来生成，通过随机数生成，并且需要存储进redis数据库中供后续判断。
    # 8.生成随机数验证码：六位
    sms_code = "%06d" % random.randint(0, 999999)
    # 9.将短信验证码存进redis中
    try:
        code_redis.setex('SMSCode-' + mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='短信存储失败')
    # 10.使用第三方扩展发送验证码
    # 调用第三方扩展且需要通过网络进行数据的发送或接收时，需要使用异常捕获模式进行调用，避免网络等方面的错误
    try:
        result = sms.CCP().send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES/60], 1)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg='短信发送异常')
    # 11.判断验证码发送是否成功
    if result == 0:
        return jsonify(errno=RET.OK, errmsg='短信发送成功')
    else:
        return jsonify(errno=RET.DATAERR, errmsg='短信发送失败')


# 3.用户注册
@passport_blu.route('/register', methods=['POST'])
def register():
    # 1.获取参数
    mobile = request.json.get('mobile')
    smscode = request.json.get('smscode')
    password = request.json.get('password')
    # 2.校验参数
    # 2.1.校验参数是否完整
    if not all([mobile, smscode, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数缺失')
    # 2.2.校验手机号格式是否正确
    if not re.match(r'^1[3456789]\d{9}$', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号格式错误')
    # 2.3.从redis数据库中获取真实验证码并进行对比
    try:
        real_smscode = code_redis.get('SMSCode-' + mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='验证码获取失败')
    if not real_smscode:
        return jsonify(errno=RET.NODATA, errmsg='验证码已失效')
    if smscode != real_smscode:
        return jsonify(errno=RET.DATAERR, errmsg='验证码不正确')
    try:
        code_redis.delete('SMSCode-' + mobile)
    except Exception as e:
        current_app.logger.error(e)
    # 2.4.判断用户密码格式是否正确
    if len(password) < 6:
        return jsonify(errno=RET.DATAERR, errmsg='密码应不小于6位')
    # 2.5.判断手机号是否注册过
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='获取用户信息失败')
    if user is not None:
        return jsonify(errno=RET.DATAEXIST, errmsg='手机号已注册')
    # 2.6.准备模型类，存储注册信息
    user = User()
    user.mobile = mobile
    user.nick_name = mobile
    user.password = password
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DATAERR, errmsg='数据存储异常')
    # 2.7.注册成功后在redis中缓存用户信息
    session['user_id'] = user.id
    session['mobile'] = user.mobile
    session['nick_name'] = user.nick_name
    # 2.8.注册成功，返回注册成功信息
    return jsonify(errno=RET.OK, errmsg='OK')


# 4.用户登录功能
@passport_blu.route('/login', methods=['POST'])
def login():
    # 1.获取参数
    mobile = request.json.get('mobile')
    password = request.json.get('password')
    # 2.校验参数
    # 2.1.判断参数是否完整
    if not all([mobile, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数缺失')
    # 2.2.校验手机号格式是否正确
    if not re.match(r'^1[3456789]\d{9}$', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号格式错误')
    # 2.3.校验密码长度是否符合要求
    if len(password) < 6:
        return jsonify(errno=RET.DATAERR, errmsg='密码长度应不小于6位')
    # 2.4.查询mysql校验手机号是否注册
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg='获取信息失败')
    # 2.5.判断手机号是否正确及密码是否正确
    if not user or not user.check_password(password):
        return jsonify(errno=RET.LOGINERR, errmsg='用户名或密码错误')
    # 2.6.登录成功需缓存用户信息到redis中
    session['user_id'] = user.id
    session['mobile'] = user.mobile
    session['nick_name'] = user.nick_name
    print('登录成功')
    # 2.7.返回前端登录成功状态码
    return jsonify(errno=RET.OK, errmsg='OK')


# 6.用户退出功能
@passport_blu.route('/logout')
def logout():
    # 用户登录即缓存了用户登录的信息，如需退出，则将缓存中信息清除即可
    session.pop('user_id')
    session.pop('mobile')
    session.pop('nick_name')
    return jsonify(errno=RET.OK, errmsg='OK')
